"""
Case Type   : DSS元数据修复工具
Case Name   : dsstbox ssrepair参数key_value值验证
Create At   : 2025/04
Owner       : haomeng
Description :
    1、查看当前卷名
    2、修改元数据,覆盖所有文件类型下所有待修改元数据
    3、修改元数据指定单个有效的key_value
    4、修改元数据指定多个有效的key_value
    5、修改元数据指定单个key_value子串超过4K,即4096字符
    6、修改元数据指定多个有效key_value,且存在子串相同字段
    7、修改元数据指定多个有效key_value,且存在重复字段
Expect      :
    1、查看成功
    2、修改成功
    3、修改成功
    4、修改成功
    5、修改失败（无单个字符串超过4k场景）
    6、修改成功，以最后一次修改值为准
    7、修改成功
History     :
"""

import os
import time
import unittest

from testcase.utils.Common import Common
from testcase.utils.CommonSH import CommonSH
from testcase.utils.Constant import Constant
from testcase.utils.Logger import Logger
from yat.test import Node
from yat.test import macro


class DSSrepairtools(unittest.TestCase):

    def setUp(self):
        self.log = Logger()
        self.log.info(f'----{os.path.basename(__file__)} start----')
        self.user_node = Node('PrimaryDbUser')
        self.pri_sh = CommonSH('PrimaryDbUser')
        self.constant = Constant()

        self.vol_path = os.path.join(macro.DSS_INSTANCE_PATH, 'cfg/dss_vg_conf.ini')
        self.dss_log_path = os.path.join(macro.DSS_INSTANCE_PATH, 'log/debug/dssinstance.dlog')
        self.file_name = 'dsstbox_ssrepair_file_013.txt'

        text = '-----prestep1:查看当前卷名;  expect:查看成功-----'
        self.log.info(text)

        res = self.user_node.sh(f"cat {self.vol_path} | awk 'NR==1'").result()
        self.log.info(res)
        self.vol_name = res.split(':')[0]
        self.vol_value = res.split(':')[1]
        self.log.info(f'vol_name的值是：{self.vol_name}, vol_value的值是：{self.vol_value}')
        self.assertNotEqual('', self.vol_name, '查看当前卷名失败')

        self.core_ctrl = ['version', 'au_size', 'volume_count',
                         'fs_block_root.version', 'fs_block_root.free.count', 'fs_block_root.free.first',
                         'fs_block_root.free.last', 'au_root.version', 'au_root.free_root', 'au_root.count',
                         'au_root.free_vol_id', 'au_root.free_list.count', 'au_root.free_list.first',
                         'au_root.free_list.last', 'fs_aux_root.version', 'fs_aux_root.free.count',
                         'fs_aux_root.free.first', 'fs_aux_root.free.last', 'volume_attrs[0].id',
                         'volume_attrs[0].size', 'volume_attrs[0].hwm', 'volume_attrs[0].free']
        self.volume_ctrl = ['version', 'defs[0].id', 'defs[0].flag', 'defs[0].version', 'defs[0].name', 'defs[0].code']
        self.root_ft_block = ['ft_block.common.type', 'ft_block.common.version','ft_block.common.id',
                              'ft_block.common.flags', 'ft_block.node_num', 'ft_block.next',
                              'ft_root.free_list.count', 'ft_root.free_list.first', 'ft_root.free_list.last',
                              'ft_root.items.count', 'ft_root.items.first', 'ft_root.items.last',
                              'ft_root.fid', 'ft_root.first', 'ft_root.last']
        self.volume_header = ['vol_type.type', 'vol_type.id', 'vol_type.entry_volume_name', 'vg_name', 'valid_flag',
                              'create_time.tv_sec', 'create_time.tv_usec', 'bak_level', 'ft_node_ratio', 'bak_ft_offset']
        self.ft_block = ['ft_node.prev', 'common.type', 'common.version', 'common.id', 'common.flags',
                         'node_num', 'next', 'ft_node.type', 'ft_node.entry', 'ft_node.name',
                         'ft_node.fid', 'ft_node.flags', 'ft_node.size', 'ft_node.written_size',
                         'ft_node.parent', 'ft_node.file_ver', 'ft_node.min_inited_size',
                         'ft_node.id', 'ft_node.next']

        self.core_ctrl_value = [3707, 8192, 2, 1, 31, 5101733957724124, 4843511, 1, 174044,
                                33025, 1, 1, 5101733957724124, 4843511, 0, 0, 0, 0, 11, 1073741824111,
                                139418664915, 10597999575022]
        self.volume_ctrl_value = [6, 0, 1, 0, f'{self.vol_value}', 1]
        self.root_ft_block_value = [0, 125, 0, 0, 1, 17408, 8094, 1724034232370176, 144097595889828864,
                                    8094, 1724034232370176, 144097595889828864, 105, 0, 144097595889828864]
        self.volume_header_value = [305419897, 0, f'{self.vol_value}', f'{self.vol_name}', 1597463007, 429496729, 1000, 1, 100, 1]
        self.ft_block_value = [1759218604459008, 0, 2036, 1741626418414592, 2, 1,
                               1759218604459008, 0, 1706442046326784, f'{self.file_name}', 6331,
                               4, 4194304, 8192, 0, 0, 0, 316659348816896, 1844674407309551615]

    def test_dsstbox(self):
        text = '-----step2:修改元数据,覆盖所有文件类型下所有待修改元数据;  expect:修改成功-----'
        self.log.info(text)

        self.log.info('-----开启debug日志;  expect:开启成功-----')
        set_debug = f"source {macro.DB_ENV_PATH};" \
                    f"dsscmd setcfg -n _log_LEVEL -v 255 -s both"
        self.log.info(set_debug)
        execute_cmd = self.user_node.sh(set_debug).result()
        self.log.info(execute_cmd)
        self.assertIn('Succeed to set cfg', execute_cmd, '开启debug日志失败')

        self.log.info('-----创建dss文件，并truncate一个大小;  expect:创建成功-----')
        touch = f"source {macro.DB_ENV_PATH};" \
                f"dsscmd touch -p +{self.vol_name}/{self.file_name}"
        self.log.info(touch)
        execute_touch = self.user_node.sh(touch).result()
        self.log.info(execute_touch)
        self.assertIn('Succeed to create file', execute_touch, '创建文件失败')

        truncate = f"source {macro.DB_ENV_PATH};" \
                   f"dsscmd truncate -p +{self.vol_name}/{self.file_name} -l 8192"
        self.log.info(truncate)
        execute_truncate = self.user_node.sh(truncate).result()
        self.log.info(execute_truncate)
        self.assertIn('Success to truncate file', execute_truncate, 'truncate文件失败')

        self.log.info('-----查看dss日志文件，筛选出创建文件的metaid;  expect:查看成功-----')
        grep_cmd = f"cat {self.dss_log_path} | grep {self.file_name} | grep metaid | tail -n 1"
        self.log.info(grep_cmd)
        grep_res = self.user_node.sh(grep_cmd).result()
        self.log.info(grep_res)

        metaid = grep_res.split('metaid')[1].split(':')[1].split(' ')[0].strip()
        self.log.info(f'metaid的值是：{metaid}')
        self.assertNotEqual('', metaid, '查看metaid失败')

        self.log.info('-----使用dsscmd showdisk查看metaid相关元数据值;  expect:查看成功-----')
        cmd = f"source {macro.DB_ENV_PATH};dsscmd showdisk -g {self.vol_name} -b {metaid} -n 0"
        self.log.info(cmd)
        execute_cmd = self.user_node.sh(cmd).result()
        self.log.info(execute_cmd)

        self.log.info('-----core_ctrl-----')
        key_value = ''
        for param in self.core_ctrl:
            key_value += f'{param}={self.core_ctrl_value[self.core_ctrl.index(param)]},'
            self.log.info(key_value)

        cmd1 = f"dsstbox ssrepair -v {self.vol_value} -t core_ctrl -k '{key_value}'"
        self.log.info(cmd1)
        execute_cmd1 = f'''source {macro.DB_ENV_PATH};yes|{cmd1}'''
        self.log.info(execute_cmd1)
        res1 = self.user_node.sh(execute_cmd1).result()
        self.log.info(res1)
        self.assertIn('Succeed to execute repair meta info', res1, '修改元数据成功')

        self.log.info('-----volume_ctrl-----')
        key_value = ''
        for param in self.volume_ctrl:
            key_value += f'{param}={self.volume_ctrl_value[self.volume_ctrl.index(param)]},'
            self.log.info(key_value)
        cmd2 = f"dsstbox ssrepair -v {self.vol_value} -t volume_ctrl -k '{key_value}'"
        self.log.info(cmd2)
        execute_cmd2 = f'''source {macro.DB_ENV_PATH};yes|{cmd2}'''
        self.log.info(execute_cmd2)
        res2 = self.user_node.sh(execute_cmd2).result()
        self.log.info(res2)
        self.assertIn('Succeed to execute repair meta info', res2, '修改元数据成功')

        self.log.info('-----root_ft_block-----')
        key_value = ''
        for param in self.root_ft_block:
            key_value += f'{param}={self.root_ft_block_value[self.root_ft_block.index(param)]},'
            self.log.info(key_value)
        cmd3 = f"dsstbox ssrepair -v {self.vol_value} -t root_ft_block -k '{key_value}'"
        self.log.info(cmd3)
        execute_cmd3 = f'''source {macro.DB_ENV_PATH};yes|{cmd3}'''
        self.log.info(execute_cmd3)
        res3 = self.user_node.sh(execute_cmd3).result()
        self.log.info(res3)
        self.assertIn('Succeed to execute repair meta info', res3, '修改元数据成功')

        self.log.info('-----volume_header-----')
        key_value = ''
        for param in self.volume_header:
            key_value += f'{param}={self.volume_header_value[self.volume_header.index(param)]},'
            self.log.info(key_value)
        cmd4 = f"dsstbox ssrepair -v {self.vol_value} -t volume_header -k '{key_value}'"
        self.log.info(cmd4)
        execute_cmd4 = f'''source {macro.DB_ENV_PATH};yes|{cmd4}'''
        self.log.info(execute_cmd4)
        res4 = self.user_node.sh(execute_cmd4).result()
        self.log.info(res4)
        self.assertIn('Succeed to execute repair meta info', res4, '修改元数据成功')

        self.log.info('-----ft_block-----')
        key_value = ''
        for param in self.ft_block:
            key_value += f'{param}={self.ft_block_value[self.ft_block.index(param)]},'
            self.log.info(key_value)
        cmd5 = f"dsstbox ssrepair -v {self.vol_value} -t ft_block -i {metaid} -s 8192 -k '{key_value}'"
        self.log.info(cmd5)
        execute_cmd5 = f'''source {macro.DB_ENV_PATH};yes|{cmd5}'''
        self.log.info(execute_cmd5)
        res5 = self.user_node.sh(execute_cmd5).result()
        self.log.info(res5)
        self.assertIn('Succeed to execute repair meta info', res5, '修改元数据成功')

        text = '-----step3:修改元数据指定单个有效的key_value;  expect:修改成功-----'
        self.log.info(text)

        cmd1 = f"dsstbox ssrepair -v {self.vol_value} -t core_ctrl -k '{self.core_ctrl[0]}={self.core_ctrl_value[0]}'"
        self.log.info(cmd1)
        execute_cmd1 = f'''source {macro.DB_ENV_PATH};yes|{cmd1}'''
        self.log.info(execute_cmd1)
        res1 = self.user_node.sh(execute_cmd1).result()
        self.log.info(res1)
        self.assertIn('Succeed to execute repair meta info', res1, '修改元数据成功')

        text = '-----step4:修改元数据指定多个有效的key_value;  expect:修改成功-----'
        self.log.info(text)

        key_value = ''
        for param in self.volume_ctrl[:5]:
            key_value += f'{param}={self.volume_ctrl_value[self.volume_ctrl.index(param)]},'
            self.log.info(key_value)

        cmd2 = f"dsstbox ssrepair -v {self.vol_value} -t volume_ctrl -k '{key_value}'"
        self.log.info(cmd2)
        execute_cmd2 = f'''source {macro.DB_ENV_PATH};yes|{cmd2}'''
        self.log.info(execute_cmd2)
        res2 = self.user_node.sh(execute_cmd2).result()
        self.log.info(res2)
        self.assertIn('Succeed to execute repair meta info', res2, '修改元数据成功')

        text = '-----step6:修改元数据指定多个有效key_value,且存在子串相同字段;  expect:修改成功-----'
        self.log.info(text)

        key_value = ''
        elements = [self.core_ctrl[0], self.core_ctrl[3], self.core_ctrl[7]]
        for param in elements:
            key_value += f'{param}={self.core_ctrl_value[self.core_ctrl.index(param)]},'
            self.log.info(key_value)

        cmd3 = f"dsstbox ssrepair -v {self.vol_value} -t core_ctrl -k '{key_value}'"
        self.log.info(cmd3)
        execute_cmd3 = f'''source {macro.DB_ENV_PATH};yes|{cmd3}'''
        self.log.info(execute_cmd3)
        res3 = self.user_node.sh(execute_cmd3).result()
        self.log.info(res3)
        self.assertIn('Succeed to execute repair meta info', res3, '修改元数据成功')

        text = '-----step7:修改元数据指定多个有效key_value,且存在重复字段;  expect:修改成功-----'
        self.log.info(text)

        key_value = ''
        for i in range(3702, 3708):
            key_value += f'{self.volume_ctrl[0]}={i},'
            self.log.info(key_value)

        cmd4 = f"dsstbox ssrepair -v {self.vol_value} -t volume_ctrl -k '{key_value}'"
        self.log.info(cmd4)
        execute_cmd4 = f'''source {macro.DB_ENV_PATH};yes|{cmd4}'''
        self.log.info(execute_cmd4)
        res4 = self.user_node.sh(execute_cmd4).result()
        self.log.info(res4)
        self.assertIn('Succeed to execute repair meta info', res4, '修改元数据成功')

    def tearDown(self):
        self.log.info('-----删除dss文件-----')
        del_cmd = f"source {macro.DB_ENV_PATH};dsscmd rm -p +{self.vol_name}/{self.file_name}"
        self.log.info(del_cmd)
        execute_del = self.user_node.sh(del_cmd).result()
        self.log.info(execute_del)
        self.assertIn(f'Succeed to remove device +{self.vol_name}/{self.file_name}', execute_del, '删除文件失败')
        self.log.info(f'----{os.path.basename(__file__)} end----')
